package edu.ccut.saturn.studio.saturndata.model;

import java.util.List;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;


import edu.ccut.saturn.component.IValidateInfo;
import edu.ccut.saturn.component.impl.SaturnValidateUseInfo;
import edu.ccut.saturn.studio.core.util.xml.SaturnW3CUtil;

public class SaturnDataModel {

	public static final String FIELD_ELEMENT_VALIDATES = "validates";
	public static final String FIELD_ATTR_LENGTH = "length";
	public static final String FIELD_ATTR_NUMBER_FORMAT = "numberFormat";
	public static final String FIELD_ATTR_DATETIME_FORMAT = "datetimeFormat";
	public static final String FIELD_ATTR_TABLE_NAME = "tableName";
	public static final String FIELD_ATTR_SEQUENCE_NAME = "sequenceName";
	public static final String FIELD_ATTR_IS_PRIMARY_KEY = "isPrimaryKey";
	public static final String FIELD_ATTR_COLUMN_ALIAS = "columnAlias";
	public static final String FIELD_ATTR_DICT_TYPE_ID = "dictTypeId";
	public static final String FIELD_ATTR_DEFAULT_VALUE = "defaultValue";
	public static final String FIELD_ATTR_SHOW_NAME = "showName";
	public static final String FIELD_ATTR_JAVA_TYPE = "javaType";
	public static final String FIELD_ATTR_COLUMN = "column";
	public static final String FIELD_ATTR_TYPE = "type";
	public static final String FIELD_ATTR_NAME = "name";
	public static final String FIELDS_ELEMENT_FIELD = "field";

	public static final String DATA_ELEMENT_FIELDS = "fields";
	public static final String DATA_ELEMENT_DESCRIPTION = "description";
	public static final String DATA_ATTR_CONNECTNAME = "connectname";
	public static final String DATA_ATTR_NAMESPACE = "namespace";
	public static final String DATA_ATTR_NAME = "name";
	public static final String DATA_ATTR_DB_TYPE = "dbType";

	public static final String ELEMENT_DATA = "data";

	private Document document;

	private ValidateModel validateXMLUtils = ValidateModel.getInstance();

	private SaturnData saturnData = null;

	/**
	 * 构造函数
	 * 
	 * @param document
	 */
	public SaturnDataModel(Document document) {
		this.document = document;
	}

	public Document getDocument() {
		return document;
	}

	public SaturnData getSaturnData() {
		if (saturnData == null) {
			Node dataNode = this.getDataNode();

			if (dataNode != null) {
				saturnData = loadBaseSaturnData(dataNode);

				Node fieldsNode = SaturnW3CUtil.getFirstChildByName(dataNode,
						DATA_ELEMENT_FIELDS);

				if (fieldsNode != null) {
					List<Node> fieldNodes = SaturnW3CUtil.getChildrenByName(
							fieldsNode, FIELDS_ELEMENT_FIELD);

					if (fieldNodes != null) {
						for (Node fieldNode : fieldNodes) {
							saturnData.addDataItem(loadDataItem(fieldNode));
						}
					}
				}
			}
		}

		return saturnData;
	}

	private Node getDataNode() {
		Element root = getDocument().getDocumentElement();

		return SaturnW3CUtil.getFirstChildByName(root, ELEMENT_DATA);
	}

	private DataItem loadDataItem(Node fieldNode) {
		DataItem dataItem = new DataItem();

		dataItem.setName(SaturnW3CUtil.getNodeAttributeValue(fieldNode,
				FIELD_ATTR_NAME));
		dataItem.setType(SaturnW3CUtil.getNodeAttributeValue(fieldNode,
				FIELD_ATTR_TYPE));
		dataItem.setColumn(SaturnW3CUtil.getNodeAttributeValue(fieldNode,
				FIELD_ATTR_COLUMN));
		dataItem.setJavaType(SaturnW3CUtil.getNodeAttributeValue(fieldNode,
				FIELD_ATTR_JAVA_TYPE));
		dataItem.setShowName(SaturnW3CUtil.getNodeAttributeValue(fieldNode,
				FIELD_ATTR_SHOW_NAME));
		dataItem.setDefaultValue(SaturnW3CUtil.getNodeAttributeValue(fieldNode,
				FIELD_ATTR_DEFAULT_VALUE));
		dataItem.setDictTypeId(SaturnW3CUtil.getNodeAttributeValue(fieldNode,
				FIELD_ATTR_DICT_TYPE_ID));
		dataItem.setDatetimeFormat(SaturnW3CUtil.getNodeAttributeValue(
				fieldNode, FIELD_ATTR_DATETIME_FORMAT));
		dataItem.setNumberFormat(SaturnW3CUtil.getNodeAttributeValue(fieldNode,
				FIELD_ATTR_NUMBER_FORMAT));
		dataItem.setColumnAlias(SaturnW3CUtil.getNodeAttributeValue(fieldNode,
				FIELD_ATTR_COLUMN_ALIAS));
		dataItem.setIsPrimaryKey(SaturnW3CUtil.getNodeAttributeValue(fieldNode,
				FIELD_ATTR_IS_PRIMARY_KEY));
		dataItem.setSequenceName(SaturnW3CUtil.getNodeAttributeValue(fieldNode,
				FIELD_ATTR_SEQUENCE_NAME));
		dataItem.setTableName(SaturnW3CUtil.getNodeAttributeValue(fieldNode,
				FIELD_ATTR_TABLE_NAME));
		dataItem.setLength(SaturnW3CUtil.getNodeAttributeValue(fieldNode,
				FIELD_ATTR_LENGTH));
		dataItem.setNumberFormat(SaturnW3CUtil.getNodeAttributeValue(fieldNode,
				FIELD_ATTR_NUMBER_FORMAT));
		dataItem.setDatetimeFormat(SaturnW3CUtil.getNodeAttributeValue(
				fieldNode, FIELD_ATTR_DATETIME_FORMAT));

		Node validatesNode = SaturnW3CUtil.getFirstChildByName(fieldNode,
				FIELD_ELEMENT_VALIDATES);

		SaturnValidateUseInfo saturnValidateUseInfo = this.validateXMLUtils
				.loadSaturnValidateUseInfo(validatesNode);
		if (saturnValidateUseInfo != null) {
			dataItem.setValidateUseInfo(saturnValidateUseInfo);
		}

		return dataItem;
	}

	private SaturnData loadBaseSaturnData(Node dataNode) {
		String name = SaturnW3CUtil.getNodeAttributeValue(dataNode,
				DATA_ATTR_NAME);
		String namespace = SaturnW3CUtil.getNodeAttributeValue(dataNode,
				DATA_ATTR_NAMESPACE);
		String dbType = SaturnW3CUtil.getNodeAttributeValue(dataNode,
				DATA_ATTR_DB_TYPE);
		String connectname = SaturnW3CUtil.getNodeAttributeValue(dataNode,
				DATA_ATTR_CONNECTNAME);
		String description = SaturnW3CUtil.getChildNodeValue(dataNode,
				DATA_ELEMENT_DESCRIPTION);

		return new SaturnData(connectname, "", description, namespace, name,
				dbType);
	}

	private Node getFieldsNode() {
		Element root = this.getDocument().getDocumentElement();

		Node dataNode = SaturnW3CUtil.getFirstChildByName(root, ELEMENT_DATA);

		if (dataNode != null) {
			return SaturnW3CUtil.getFirstChildByName(dataNode,
					DATA_ELEMENT_FIELDS);
		}

		return null;
	}

	private List<Node> getFieldNodes() {
		Node fieldsNode = this.getFieldsNode();

		if (fieldsNode != null) {
			return SaturnW3CUtil.getChildrenByName(fieldsNode,
					FIELDS_ELEMENT_FIELD);
		}

		return null;
	}

	public void addDataItem(DataItem dataItem) {
		Node fieldsNode = getFieldsNode();

		Node fieldNode = SaturnW3CUtil.createChildNode(fieldsNode,
				FIELDS_ELEMENT_FIELD, null);
		createDataItem(fieldNode, dataItem);

		SaturnW3CUtil.format(fieldNode.getParentNode());
		
		if (this.saturnData != null) {
			this.saturnData.addDataItem(dataItem);
		}
	}

	public void removeDataItem(DataItem dataItem) {
		String id = dataItem.getId();

		Node field = this.findFiledById(id);

		if (field != null) {
			field.getParentNode().removeChild(field);
		}
		
		if (this.saturnData != null) {
			this.saturnData.removeDataItem(dataItem);
		}
	}

	public Node findFiledById(String id) {
		List<Node> fields = this.getFieldNodes();

		if (fields != null) {
			for (Node field : fields) {
				String fieldId = getFieldId(field);

				if (fieldId.equals(id)) {
					return field;
				}
			}
		}

		return null;
	}

	private String getFieldId(Node field) {
		String fieldname = SaturnW3CUtil.getNodeAttributeValue(field,
				FIELD_ATTR_NAME)
				+ SaturnW3CUtil.getNodeAttributeValue(field, FIELD_ATTR_COLUMN)
				+ SaturnW3CUtil.getNodeAttributeValue(field,
						FIELD_ATTR_TABLE_NAME);
		return fieldname;
	}

	private void createDataItem(Node fieldNode, DataItem dataItem) {
		this.createBaseDataItemNode(fieldNode, dataItem);
		this.validateXMLUtils.createValidateUseInfo(fieldNode, dataItem);
	}

	private void createBaseDataItemNode(Node fieldNode, DataItem dataItem) {
		SaturnW3CUtil.createAttribute(fieldNode, FIELD_ATTR_NAME, dataItem
				.getName());
		SaturnW3CUtil.createAttribute(fieldNode, FIELD_ATTR_LENGTH, dataItem
				.getLength());
		SaturnW3CUtil.createAttribute(fieldNode, FIELD_ATTR_TYPE, dataItem
				.getType());
		SaturnW3CUtil.createAttribute(fieldNode, FIELD_ATTR_COLUMN, dataItem
				.getColumn());
		SaturnW3CUtil.createAttribute(fieldNode, FIELD_ATTR_JAVA_TYPE, dataItem
				.getJavaType());
		SaturnW3CUtil.createAttribute(fieldNode, FIELD_ATTR_SHOW_NAME, dataItem
				.getShowName());
		SaturnW3CUtil.createAttribute(fieldNode, FIELD_ATTR_DEFAULT_VALUE,
				dataItem.getDefaultValue());
		SaturnW3CUtil.createAttribute(fieldNode, FIELD_ATTR_DICT_TYPE_ID,
				dataItem.getDictTypeId());
		SaturnW3CUtil.createAttribute(fieldNode, FIELD_ATTR_DATETIME_FORMAT,
				dataItem.getDatetimeFormat());
		SaturnW3CUtil.createAttribute(fieldNode, FIELD_ATTR_NUMBER_FORMAT,
				dataItem.getNumberFormat());
		SaturnW3CUtil.createAttribute(fieldNode, FIELD_ATTR_COLUMN_ALIAS,
				dataItem.getColumnAlias());
		SaturnW3CUtil.createAttribute(fieldNode, FIELD_ATTR_IS_PRIMARY_KEY,
				dataItem.getIsPrimaryKey());
		SaturnW3CUtil.createAttribute(fieldNode, FIELD_ATTR_SEQUENCE_NAME,
				dataItem.getSequenceName());
		SaturnW3CUtil.createAttribute(fieldNode, FIELD_ATTR_TABLE_NAME, dataItem
				.getTableName());
	}

	public void changeDataNodeValue(String nodeName, String value) {
		Node dataNode = this.getDataNode();

		Node child = SaturnW3CUtil.getFirstChildByName(dataNode, nodeName);
		if (child != null) {
			dataNode.removeChild(child);
		}

		SaturnW3CUtil.createChildNode(dataNode, nodeName, value);
	}

	public void changeDataAttributeValue(String attributeName, String value) {
		Node dataNode = this.getDataNode();

		SaturnW3CUtil.createAttribute(dataNode, attributeName, value);
	}

	public void changeFiledAttributeValue(String fieldId, String attrName,
			String value) {

		Node fieldNode = this.findFiledById(fieldId);

		if (fieldNode != null) {
			SaturnW3CUtil.createAttribute(fieldNode, attrName, value);
			SaturnW3CUtil.format(fieldNode.getParentNode());
		}
	}

	public void changeValidateUseAttributeValue(String fieldId,
			String attrName, String value) {

		Node fieldNode = this.findFiledById(fieldId);

		if (fieldNode != null) {
			Node validateUseNode = SaturnW3CUtil.getFirstChildByName(fieldNode,
					FIELD_ELEMENT_VALIDATES);
			SaturnW3CUtil.createAttribute(validateUseNode, attrName, value);
		}
	}

	public void changeValidates(String fieldId,
			List<IValidateInfo> validateInfos) {
		Node fieldNode = this.findFiledById(fieldId);

		if (fieldNode != null) {
			Node validatesNode = SaturnW3CUtil.getFirstChildByName(fieldNode,
					FIELD_ELEMENT_VALIDATES);
			SaturnW3CUtil.removeChildren(validatesNode);

			if (validateInfos != null) {
				for (IValidateInfo validateInfo : validateInfos) {
					this.validateXMLUtils.createValidateInfoNode(validatesNode,
							validateInfo);
				}
			}

			SaturnW3CUtil.format(fieldNode.getParentNode());
		}
	}
}
